/* 
 * File:   Boss.cpp
 * Author: paula
 * 
 * Created on 29 de noviembre de 2014, 15:50
 */

#include "Boss.h"

Boss::Boss() {
}

Boss::Boss(ObjFactory *objFactory, int x, int y) {

    this->myLogFile->getInstance(MY_LOG_MODE);
    this->objFactory = objFactory;
    this->windowUnitWidth = this->objFactory->getUnitWidth();
    this->windowUnitHeight = this->objFactory->getUnitHeight();

    this->objWidth = 500;
    this->objHeight = 500;

    Dot *dotito = new Dot(x, y, objWidth, objHeight);

    this->dot = dotito;
    Object *object = objFactory->getCharacter(this->dot->dotPixelsToWorld(), this->dot->sizeDotPixelsToWorld());
    this->object = object;
    //    b2MassData mass;
    //    mass.mass = 10000.0;
    //    this->object->getBody()->SetMassData(&mass);
    //set UserData
    b2Fixture* fixtt = this->object->getBody()->GetFixtureList();
    fixtt->SetUserData((void*) THE_BOSS);
    fixtt = fixtt->GetNext();
    fixtt->SetUserData((void*) THE_BOSS);

    b2Vec2 vecc(object->getPosition().x, object->getPosition().y);
    this->posInitial = vecc;

    this->directionRight = true;
    this->counterAttacked = 1;
    this->counterAttack = 1;
    this->counterJump = 1;
    this->counterWait = 9;
    this->beginning = true;
    this->jumping = false;
    this->attacking = false;
    this->attacked = false;
    this->fallingDown = false;
    this->wasJumping = false;
    this->lastPosY = 0;
    this->currentPosY = 0;
    this->lastVelY = 0;
    this->currentVelY = 0;
    this->initConsFall = 3;
    this->constFall = initConsFall;

    this->score = INITIAL_SCORE;
    this->lifes = BOSS_INITIAL_LIFES;

    // inicializo data 
    struct ObjectInit obj;
    obj.x = x;
    obj.y = y;
    obj.stateCharacter = this->getState();
    obj.estatico = false;
    obj.objectId = VACIO;
    obj.idCharacter = 21;
    obj.width = this->objWidth;
    obj.height = this->objHeight;
    //    obj.lifes = this->lifes;
    //    obj.score = this->score;
    this->data = obj;

    this->lastState = 0;

    this->equals = false;
    this->wasJumping = false;

    //SHOOT
    //    SnowGun *weapon = new SnowGun(objFactory);
    //    this->weapon = weapon;
    
    this->contSend = 0;

}

Boss::Boss(const Boss& orig) {
}
void Boss::restartPlayer(){}
float Boss::getPosX() {
    this->actualizePosition();
    return this->dot->getPos()->x;
}

float Boss::getPosY() {
    this->actualizePosition();
    return this->dot->getPos()->y;
}

int Boss::getState() {

    if (isJumping()) {
        return JUMPING;
    }
    if (isAttacking()) {
        return ATTACKING;
    }
    if (isBeingAttacked()) {
        return ATTACKED;
    }
    if (isFallingDown()) {
        return FALLING;
    } else {
        return WAITING;
    }
}

b2Body* Boss::getBody() {
    return this->object->getBody();
}

int Boss::getUbicDyn() {
    return this->data.ubicDyn;
}

bool Boss::isJumping() {
    return this->jumping;
}

bool Boss::isAttacking() {
    return this->attacking;
}

bool Boss::isBeingAttacked() {
    return this->attacked;
}

bool Boss::isFallingDown() {

    float velY2;
    velY2 = this->object->getBody()->GetLinearVelocity().y;
    if (velY2 == 0) {
        return false;
    }

    this->fallingDown = true;

    if (wasJumping) {
        if (this->object->getBody()->GetLinearVelocity().y <= 0.05) {
            wasJumping = true;
        } else {
            wasJumping = false;
        }

        //        b2Fixture* fixt = this->object->getBody()->GetFixtureList();
        //        if (fixt->IsSensor()) {
        //            fixt = fixt->GetNext();
        //        }
        //        b2Filter filter = fixt->GetFilterData();
        //        filter.groupIndex = GROUPINDEXCHARACTER;
        //        fixt->SetFilterData(filter);

        return fallingDown;

    } else {

        b2Body* body = this->object->getBody();

        for (b2ContactEdge* contList = body->GetContactList(); contList; contList = contList->next) {
            b2Contact* cont = contList->contact;
            b2Fixture* fixtA = cont->GetFixtureA();
            b2Fixture* fixtB = cont->GetFixtureB();
            void* dataVoidA = fixtA->GetUserData();
            int data = *((int*) &dataVoidA);
            if (data == IS_FLOOR && fixtB->IsSensor() && (this->object->getBody()->GetLinearVelocity().y < 0.05)) {
                this->fallingDown = false;
                constFall = initConsFall;
            }
            void* dataVoidB = fixtB->GetUserData();
            data = *((int*) &dataVoidB);
            if (data == IS_FLOOR && fixtA->IsSensor() && (this->object->getBody()->GetLinearVelocity().y < 0.05)) {
                this->fallingDown = false;
                constFall = initConsFall;
            }
        }

        //        if (this->fallingDown) {
        //            b2Fixture* fixt = this->object->getBody()->GetFixtureList();
        //            if (fixt->IsSensor()) {
        //                fixt = fixt->GetNext();
        //            }
        //            b2Filter filter = fixt->GetFilterData();
        //            filter.groupIndex = GROUPINDEXCHARACTER;
        //            fixt->SetFilterData(filter);
        //        }
        return this->fallingDown;
    }
}

void Boss::actualizePosition() {
    b2Vec2 currentPos = (this->object->getPosition());
    this->dot->setPos(currentPos.x, currentPos.y);
}

void Boss::keepFallingDown() {
    this->actualizePosition();
}

void Boss::wait() {

    attacking = false;
    counterAttack = 1;
    this->actualizePosition();
    b2Vec2 vec = this->object->getPosition();
    if (this->isFallingDown()) {
        this->keepFallingDown();
    } else {
        if (counterWait > 8) {
        } else {
            counterWait++;

        }
        if (counterWait > 100) {
            counterWait = 9;
        }
    }
}

void Boss::jump() {

    this->beginning = false;
    counterJump++;
    jumping = true;
    attacking = false;
    counterAttack = 1;
    this->actualizePosition();
    counterJump++;

}

void Boss::attack() {

    this->actualizePosition();
    beginning = false;
    counterAttack++;
    if (counterAttack >= 2) {
        attacking = true;
        counterAttack++;
    }
}

void Boss::beAttacked() {

    this->actualizePosition();
    beginning = false;
    counterAttacked++;
    this->attacked = true;
    this->lifes--;
    //    if (counterAttack >= 2) {
    //        attacking = true;
    //        counterAttack++;
    //    }
}

void Boss::updateState() {
    this->data.stateCharacter = this->getState();
    this->data.direction = this->directionRight;
}

void Boss::updateData() {

    this->updatePosition();
    this->updateState();
    //    this->data.lifes = this->lifes;
    //    this->data.score = this->score;
}

void Boss::setUbicDyn(int id) {
    this->data.ubicDyn = id;
}

struct ObjectInit Boss::getData() {
    this->updateData();
    this->data.level=0;
    return this->data;
}

void Boss::checkChanges() {
    b2Vec2 pos = this->object->getPosition();

    if (this->data.x == pos.x && this->data.y == pos.y) {
        this->equals = true;
    } else {
        this->equals = false;
    }
}

bool Boss::getAreEquals() {
    if (this->contSend != 0){
        this->contSend = 0;
        return false;
    }
    if (this->equals && (this->lastState == this->data.stateCharacter)) {
        return true;
    } else {
        this->lastState = this->data.stateCharacter; // actualizo para siguiente vuelta
        this->contSend = 1;
        return false;
    }

}

void Boss::beRandom() {

    switch (this->getState()) {
        case JUMPING:
            this->keepJumping();
            break;
        case ATTACKING:
            this->keepAttacking();
            break;
        case ATTACKED:
            this->keepAttacked();

            break;
        case FALLING:
            this->keepFallingDown();
            break;
        case WAITING:

            int randomNumber = rand() % 500;
            if ((randomNumber == 0) || (randomNumber == 2) || (randomNumber == 3))  {
                this->attack();
                
            }
            if ((randomNumber == 1) || (randomNumber == 2) || (randomNumber == 3) || (randomNumber == 4)) {
                this->jump();

            }
            
            break;
    }
}

void Boss::keepAttacking() {
    this->actualizePosition();
    counterAttack++;
    if (counterAttack > 55) {
        this->attacking = false;
        this->counterAttack = 0;
    }
}

void Boss::keepAttacked() {
    this->actualizePosition();
    counterAttacked++;
    if (counterAttacked > 55) {
        this->attacked = false;
        this->counterAttacked = 0;
    }
}

void Boss::keepJumping() {

    this->actualizePosition();
    switch (this->counterJump) {
        case (3):
            counterJump++;
            break;
        case (4):
            counterJump++;
            break;
        case (5):
            counterJump++;
            break;
        case (6):
            counterJump++;
            break;
        case (7):
            this->jumpUp();
            counterJump++;
            break;
        case (8):
            this->jumpUp();
            counterJump++;
            break;
        case (9):
            float velY;
            velY = this->object->getBody()->GetLinearVelocity().y;
            if (velY > -2) {
                counterJump = 1;
                jumping = false;
                wasJumping = true;
            }
            break;
        default:
            float velY2;
            velY2 = this->object->getBody()->GetLinearVelocity().y;
            if (velY2 == 0) {
                counterJump = 1;
                jumping = false;
                wasJumping = true;
            }
            break;
    }
}

void Boss::jumpUp() {
    b2Body* body = this->object->getBody();
    b2Vec2 velocity(0, (-5.2f));
    body->SetLinearVelocity(velocity);
}

void Boss::updatePosition() {
    this->data.x = this->getPosX();
    this->data.y = this->getPosY();
}

void Boss::updateRotation() {
    // no tiene rotacion
}

bool Boss::inConctactBullet() {
    bool contacBullet = false;
    b2Body* body = this->getBody();
    for (b2ContactEdge* contList = body->GetContactList(); contList; contList = contList->next) {
        b2Contact* cont = contList->contact;
        b2Fixture* fixtA = cont->GetFixtureA();
        b2Fixture* fixtB = cont->GetFixtureB();
        void* dataVoidA = fixtA->GetUserData();
        int data = *((int*) &dataVoidA);
        if (data == IS_BULLET) { //contacto con una bala.            
            contacBullet = true;
        }
        void* dataVoidB = fixtB->GetUserData();
        data = *((int*) &dataVoidB);
        if (data == IS_BULLET) { //contacto con una bala.                        
            contacBullet = true;
        }
    }
    return contacBullet;
}

bool Boss::isAlive(){
//    cout << "this->lifes: " << this->lifes << endl;
    if (this->lifes <= 0){
        return false;
    }
    return true;
}

Boss::~Boss() {
}

